package net.pws.common.security.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.pws.common.security.SecurityContext;
import net.pws.common.security.spi.Principal;

import org.apache.commons.lang.StringUtils;


public abstract class AbstractAuthenticateFilter implements Filter {
    
    public static final String AUTHENTICATED_SUCCEED_KEY = "com.xlbs.common.security.filter#AUTHENTICATED_SUCCEED";
    
    public static final String BASIC_AUTH_USERNAME_KEY = "j_username";
    
    public static final String BASIC_AUTH_PASSWORD_KEY = "j_password";
    
    public static final String BASIC_AUTH_FILTER_URL = "/j_security_check";
    
    public static final String AUTH_TOKEN_KEY = "AUTH_TOKEN";
    
    private String loginPage = "/login.jsp";
    
    private String homePage = "/index.jsp";
    
    private String noPermissionPage = "/no.permission.html";
    
    private String securityCheckUrl = BASIC_AUTH_FILTER_URL;
    
    public String getSecurityCheckUrl() {
        return securityCheckUrl;
    }
    
    public void setSecurityCheckUrl(String securityCheckUrl) {
        this.securityCheckUrl = securityCheckUrl;
    }
    
    protected String getUserName(HttpServletRequest request) {
        return request.getParameter(BASIC_AUTH_USERNAME_KEY);
    }
    
    protected String getPassword(HttpServletRequest request) {
        return request.getParameter(BASIC_AUTH_PASSWORD_KEY);
    }
    
    protected String currentUserId() {
    	Principal princpal = SecurityContext.getContext();
		if (princpal == null) {
			return null;
		}
		return princpal.getId();
	}
    
    public String getLoginPage() {
        return loginPage;
    }
    
    public void setLoginPage(String loginPage) {
        this.loginPage = loginPage;
    }
    
    public String getHomePage() {
        return homePage;
    }
    
    public void setHomePage(String protectedIndexPage) {
        this.homePage = protectedIndexPage;
    }
    
    public String getNoPermissionPage() {
        return noPermissionPage;
    }

    public void setNoPermissionPage(String noPermissionPage) {
        this.noPermissionPage = noPermissionPage;
    }

    public void destroy() {
    }
    
    public void init(FilterConfig config) throws ServletException {
        
    }
    
    protected String determineAuthType(ServletRequest request) {
        return ((HttpServletRequest) request).getHeader("Auth-Type");
    }
    
    protected String determineAuthType(ServletRequest request,
                                       String defaultValue) {
        
        String result = ((HttpServletRequest) request).getHeader("Auth-Type");
        if (StringUtils.isEmpty(result)) {
            return defaultValue;
        }
        return result;
    }
    
    protected String determineAccessType(ServletRequest request) {
        return ((HttpServletRequest) request).getHeader("Access-Type");
    }
    
    protected String determineAccessType(ServletRequest request,
                                         String defaultValue) {
        String result = ((HttpServletRequest) request).getHeader("Access-Type");
        if (StringUtils.isEmpty(result)) {
            return defaultValue;
        }
        return result;
    }
    
    protected void sendRedirect(HttpServletRequest request,
                                HttpServletResponse response,
                                String url) throws IOException {
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
            url = request.getContextPath() + url;
        }
        
        response.sendRedirect(response.encodeRedirectURL(url));
    }
    
    protected boolean matches(HttpServletRequest request,
                              HttpServletResponse response,
                              String target) {
        String uri = request.getRequestURI();
        int pathParamIndex = uri.indexOf(';');
        
        if (pathParamIndex > 0) {
            // strip everything after the first semi-colon
            uri = uri.substring(0, pathParamIndex);
        }
        
        if (StringUtils.isEmpty(request.getContextPath())) {
            return uri.endsWith(target);
        }
        
        return uri.endsWith(request.getContextPath() + target);
    }
    
    protected boolean matchStart(HttpServletRequest request,
                                 HttpServletResponse response,
                                 String target) {
        String uri = request.getRequestURI();
        int pathParamIndex = uri.indexOf(';');
        
        if (pathParamIndex > 0) {
            // strip everything after the first semi-colon
            uri = uri.substring(0, pathParamIndex);
        }
        
        if (StringUtils.isEmpty(request.getContextPath())) {
            return uri.startsWith(target);
        }
        
        return uri.startsWith(request.getContextPath() + target);
    }
    
    protected String determineAuthTokenValue(HttpServletRequest request) {
        String result = determineAuthTokenValueByCookie(request);
        if (StringUtils.isEmpty(result)) {
            return determineAuthTokenValueByParameter(request);
        }
        return result;
    }
    
    protected String determineAuthTokenValueByCookie(HttpServletRequest request,
                                                     String cookieName) {
        Cookie[] cookies = request.getCookies();
        
        if (null == cookies) {
            return null;
        }
        
        for (int i = 0; i < cookies.length; i++) {
            if (cookieName.equals(cookies[i].getName())) {
                return cookies[i].getValue();
            }
        }
        
        return null;
    }
    
    protected String determineAuthTokenValueByCookie(HttpServletRequest request) {
        return determineAuthTokenValueByCookie(request, AUTH_TOKEN_KEY);
    }
    
    protected String determineAuthTokenValueByParameter(HttpServletRequest request) {
        return request.getParameter(AUTH_TOKEN_KEY);
    }
    
    public static Cookie getCookie(HttpServletRequest request, String name) {
        Cookie cookies[] = request.getCookies();
        // Return null if there are no cookies or the name is invalid.
        if (cookies == null || name == null || name.length() == 0) {
            return null;
        }
        // Otherwise, we do a linear scan for the cookie.
        for (int i = 0; i < cookies.length; i++) {
            if (cookies[i].getName().equals(name)) {
                return cookies[i];
            }
        }
        return null;
    }
    
    public static String getCookieValue(HttpServletRequest request, String name) {
        Cookie cookie = getCookie(request, name);
        if (cookie == null) {
            return null;
        }
        
        String value = cookie.getValue();
        if (value != null) {
            try {
                value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
            }
            catch (UnsupportedEncodingException ex) {
            }
        }
        
        return value;
    }
    
    public static void saveCookie(HttpServletResponse response,
                                  String name,
                                  String value,
                                  int saveTime) {
        Cookie cookie = new Cookie(name, value);
        cookie.setMaxAge(saveTime);
        cookie.setPath("/");
        response.addCookie(cookie);
    }
    
    /**
     * Invalidates the specified cookie.
     */
    public static void deleteCookie(HttpServletResponse response,
                                    String cookieName) {
        // invalidate the cookie
        Cookie cookie = new Cookie(cookieName, null);
        // delete the cookie when the user closes their webbrowser
        cookie.setMaxAge(0);
        cookie.setPath("/");
        response.addCookie(cookie);
    }
    
}
